package com.example.terminal;

import java.io.File;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.example.bean.UDPSendPackage;
import com.example.constant.ClientConstants;
import com.example.manager.bean.MHEARTBEAT;
import com.example.manager.bean.TREG;
import com.example.manager.bean.TREGRESULT;
import com.example.sender.TcpSender;
import com.example.sender.UDPSender;
import com.example.terminal.bean.THEARTBEAT;
import com.example.terminal.bean.TTOMANAGER;
import com.example.terminal.bean.VMESS;
import com.example.type.StreamType;
import com.example.util.DataBuilder;
import com.example.util.Des;
import com.example.util.DeviceFactory;
import com.example.util.TcpRequestController;

public class TerminalClient {

	private final static Logger log = LoggerFactory.getLogger(TerminalClient.class);
	
	/**
	 * 实例序号，从0开始
	 */
	private static int no = 0;
	
	/**
	 * 心跳发送间隔，默认200毫秒
	 */
	private int heartBeatInterval = 200;
	
	protected boolean shutdown = true;
	
	protected DatagramSocket xt_sendsocket;
	
	protected String macid;
	
	protected String deviceId;
	
	/**
	 * 录制端id
	 */
	protected int terminalId;
	
	protected DatagramSocket p2p_v_sendsocket; // 视频
	
	protected DatagramSocket p2p_r_sendsocket; //音频
	
	/*** 中转服务器的ip/穿透时m的ip **/
	protected String nip = "";
//	protected String vport = "9001";
//	protected String rport = "9002";
	protected String vport = "";
	protected String rport = "";	
//	/**
//	 * 默认100毫秒
//	 */
//	protected int p2pSocketTimeout = 100;
	
	protected boolean recordrun = false; // 录音线程是否结束
	
	/*** M端的最后一次心跳的接收时间，用来判断M是否还在线 */
	protected long lasttime;
	
	/*** 视频穿透尝试次数 */
	protected int times_v = 0;
	
	/*** UPD接受和发送 **/
	private UDPSender udpsender;
	
	protected TcpSender tcpSender;
	
	public long sendPackages;
	
	protected final static int SOCKET_TIMEOUT = 30 * 1000;
	
	public TerminalClient(int socketTimeout, String macid) throws Exception {
		shutdown = false;
		deviceId = DeviceFactory.createDeviceId();;
		this.macid = macid;
		xt_sendsocket = new DatagramSocket();
		
//		p2p_v_sendsocket = new DatagramSocket(Integer.parseInt(vport));
		p2p_v_sendsocket = new DatagramSocket();
		p2p_v_sendsocket.setSoTimeout(socketTimeout);
		
//		p2p_r_sendsocket = new DatagramSocket(Integer.parseInt(rport));
		p2p_r_sendsocket = new DatagramSocket();
		p2p_r_sendsocket.setSoTimeout(socketTimeout);
		
		synchronized(this){
			no++;
		}
	}
	
	public TerminalClient(int socketTimeout) throws Exception {
		this(SOCKET_TIMEOUT, DataBuilder.buildLocalMacAddress());
	}
	
	public TerminalClient(String macid) throws Exception {
		this(SOCKET_TIMEOUT, macid);
	}
	
	public TerminalClient() throws Exception {
		this(SOCKET_TIMEOUT);
	}
	
	public void start() {
		initHeartBeat(0);
		listenManagerHeartBeat();
		new P2P_V_Thread().start();
	}
	
	public void start(int heartBeatCount) {
		initHeartBeat(heartBeatCount);
		listenManagerHeartBeat();
		new P2P_V_Thread().start();
	}
	
	public void shutdown(){
		shutdown = true;
	}
	
	public TREGRESULT register(){
		TREG reg = new TREG();
		reg.tmacid = macid;
		reg.actiontype = "1";
		TREGRESULT result = new TREGRESULT();
		result = (TREGRESULT)TcpRequestController.GetResultByParam(reg, result, ClientConstants.ip, ClientConstants.tport);
		
		terminalId = Integer.valueOf(result.query);
		
		log.info("terminal[{}] id is {}", no, result.query);
		
		return result;
	}
	
	public TREGRESULT getAttachedManger(int terminalId){
		return connectPort2021(terminalId, "2");
	}
	
	public TREGRESULT getAttachedManger(){
		return getAttachedManger(terminalId);
	}
	
	public TREGRESULT getManagerStatus(){
		return connectPort2021(terminalId, "3");
	}
	
	/**
	 * 发送心跳
	 * @throws Exception
	 */
	public void initHeartBeat(final int count) {
		new Thread(){
			@Override
			public void run(){
				try{
					int c = 0;
					
					while(!shutdown){
//						log.debug("count = {}, c = {}", count, c);
						if(count != 0 && c >= count){
							break;
						}else{
							c++;
						}
						
						THEARTBEAT theartbeat = new THEARTBEAT();
						theartbeat.actiontype = "1";
						theartbeat.tstate = "2";
						theartbeat.tid = String.valueOf(terminalId);
						theartbeat.tjip = String.valueOf(ClientConstants.ip);
						theartbeat.tmac = DataBuilder.buildLocalMacAddress();
						
						String xt;
						String key = ClientConstants.key;
						String json = DataBuilder.buildJson(theartbeat);
						
						xt = Des.encryptDES(json, key, key);
						DatagramPacket pack = new DatagramPacket(xt.getBytes(), xt.getBytes().length, InetAddress.getByName(ClientConstants.ip), ClientConstants.xtport);
						xt_sendsocket.send(pack);
						log.debug("send heart beat json to {}", theartbeat.tjip);
						log.debug("data -> {}", json);
						
						log.debug("heart beat response data -> {}", Des.decryptDES(new String(pack.getData()), key, ClientConstants.iv));
						
						Thread.sleep(heartBeatInterval);
						
						
					}
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}.start();
	}

	/**
	 * 接受M心跳
	 */
	public void listenManagerHeartBeat(){
		Thread t = new Thread(new Runnable(){
			public void run() {
				try{
					while(!shutdown){
						String key = ClientConstants.key;
						byte[] buffer = new byte[1500];
						DatagramPacket pack = new DatagramPacket(buffer, buffer.length);
						xt_sendsocket.receive(pack);
						
						log.debug("received M response -> {}", Des.decryptDES(new String(pack.getData()), key, ClientConstants.iv));
						
						String s = new String(buffer);
						VMESS vmess = new VMESS();
						vmess = DataBuilder.buildObject(Des.decryptDES(String.valueOf(s), key, key), vmess);
						
						if (vmess.actiontype.equals("-1")) {
							log.debug("收到了状态服务器返回的心跳");
						} else if (vmess.actiontype.equals("0")) {
//							if (MyApplication.getInstance().getMainactivity() != null) {
//								Handler hanlder = MyApplication.getInstance()
//										.getMainactivity().getmMainHandler();
//								Message msg = new Message();
//								Bundle data = new Bundle();
//								data.putString("mid", vmess.mid);
//								msg.setData(data);
//								msg.what = 4;
//								hanlder.sendMessage(msg);
//							}
						} else if (vmess.actiontype.equals("90")) {
//							if (MyApplication.getInstance().getMainactivity() != null) {
//								Handler hanlder = MyApplication.getInstance()
//										.getMainactivity().getmMainHandler();
//								Message msg = new Message();
//								Bundle data = new Bundle();
//								data.putString("mid", vmess.mid);
//								data.putString("mip", vmess.ip);
//								data.putString("vport", vmess.vport);
//								msg.setData(data);
//								msg.what = 5;
//								hanlder.sendMessage(msg);
//							}
							log.info("视频端口穿透");
						} else if (vmess.actiontype.equals("91")) {
//							if (MyApplication.getInstance().getMainactivity() != null) {
//								Handler hanlder = MyApplication.getInstance()
//										.getMainactivity().getmMainHandler();
//								Message msg = new Message();
//								Bundle data = new Bundle();
//								data.putString("mid", vmess.mid);
//								data.putString("mip", vmess.ip);
//								data.putString("vport", vmess.vport);
//								msg.setData(data);
//								msg.what = 6;
//								hanlder.sendMessage(msg);
//							}
							log.info("音频端口穿透");
						}else if(vmess.actiontype.equals("20")){
//							if (MyApplication.getInstance().getMainactivity() != null) {
//								Handler hanlder = MyApplication.getInstance()
//										.getMainactivity().getmMainHandler();
//								
//								Message msg = new Message();
//								Bundle data = new Bundle();
//								data.putString("content", vmess.content);
//								msg.setData(data);
//								msg.what = 7;
//								hanlder.sendMessage(msg);
//							}
							sendOrder(vmess.mid);
							//回复给m
							log.info("收到了m的命令");
						}
						
					}
				}catch(Exception e){
					
				}
			}
		});
		t.start();
	}
	
	public void requestAVIPAndPort(int mCode) throws Exception {
		requestAVIPAndPort(mCode, null);
	}
	
	/**
	 * 请求中转管理服务器分配ip port
	 * @param mCode
	 * @throws Exception
	 */
	public void requestAVIPAndPort(int mCode, String md5) throws Exception {
		requestAVIPAndPort(mCode, terminalId, md5);
	}
	
	/**
	 * 请求中转管理服务器分配ip port
	 * @param mCode
	 * @param tCode
	 * @throws Exception
	 */
	public void requestAVIPAndPort(int mCode, int tCode, String md5) throws Exception {
		TTOMANAGER ttomanager = new TTOMANAGER();
		ttomanager.actiontype = "56";
		ttomanager.mt = mCode + "_" + tCode;
		ttomanager.self = "T";
		ttomanager.md5 = md5;
		String key = ClientConstants.key;
		String r = Des.encryptDES(DataBuilder.buildJson(ttomanager), key, key);
		DatagramPacket temp_m = new DatagramPacket(r.getBytes(), r.getBytes().length, InetAddress.getByName(ClientConstants.managerip), ClientConstants.managerport);
		p2p_v_sendsocket.send(temp_m);
		log.debug("第一步，收到了指令，需要发送消息给中转管理");
	}
	
	public void sendVedio(File file) throws Exception {
		while(udpsender == null){
			Thread.sleep(500);
		}
		udpsender.sendStream(file, StreamType.Vedio, this);
	}
	
	public void sendVedio(int tid, int total, int no) throws Exception {
		while(udpsender == null){
			Thread.sleep(500);
		}
		udpsender.sendVedio(tid, total, no);
	}
	
	public void sendFile(File file) throws Exception {
		while(tcpSender == null){
			Thread.sleep(500);
		}
		
		tcpSender.sendStream(file);
	}
	
	public void sendOrder(final String mid) throws Exception {
		new Thread(){
			@Override
			public void run(){
				try{
					MHEARTBEAT temp = new MHEARTBEAT();
					temp.actiontype = "20";
					temp.mid = mid;
					temp.tid = macid;
					temp.content = "huifud哈哈";
					
					String xtjson;
					String key = ClientConstants.key;
					xtjson = Des.encryptDES(DataBuilder.buildJson(temp), key,key);
					DatagramPacket pack = new DatagramPacket(
							xtjson.getBytes(), xtjson.getBytes().length,
							InetAddress.getByName(ClientConstants.ip),ClientConstants.xtport);
					xt_sendsocket.send(pack);
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}.start();
	}
	
	protected TREGRESULT connectPort2021(int terminalId, String actiontype){
		TREG reg = new TREG();
		reg.tmacid = String.valueOf(terminalId);
		reg.actiontype = actiontype;
		TREGRESULT result = new TREGRESULT();
		result = (TREGRESULT)TcpRequestController.GetResultByParam(reg, result, ClientConstants.ip, ClientConstants.tport);
		
		return result;
	}

	/*** 视频 消息接收线程 **/
	class P2P_V_Thread extends Thread {
		@Override
		public void run() {
			while (!shutdown) {
				try {
					byte[] v_buffer = new byte[600];
					DatagramPacket pack = new DatagramPacket(v_buffer, v_buffer.length);
					p2p_v_sendsocket.receive(pack);
					String s = new String(v_buffer);

					VMESS vmess = new VMESS();
					String key = ClientConstants.key;
					vmess = DataBuilder.buildObject(Des.decryptDES(String.valueOf(s), key, key), vmess);
					
					log.debug("terminal vedio thread received response -> {}", vmess);
					
					if (vmess.actiontype.equals("1")) {
						nip = vmess.ip;
						vport = vmess.vport;
						rport = vmess.rport;
//						mMainHandler.sendEmptyMessage(0);
						if("1".equals(vmess.contenttype)){
							// 传文件
							tcpSender = new TcpSender(nip, Integer.valueOf(vport));
							log.info("created tcp sender");
						}else{
							udpsender = new UDPSender(nip, Integer.valueOf(vport), Integer.valueOf(rport), p2p_v_sendsocket, p2p_r_sendsocket);
						}
						
						log.debug("第二步，收到n的ip和端口。");
					} else if (vmess.actiontype.equals("11")) {
						// 局域网,m->t
						VMESS tempvmess = new VMESS();
						tempvmess.actiontype = "12";
						String p2p_lan_sendm = Des.encryptDES(DataBuilder.buildJson(tempvmess), key, key);
						DatagramPacket temppack = new DatagramPacket(
								p2p_lan_sendm.getBytes(),
								p2p_lan_sendm.getBytes().length,
								pack.getAddress(), pack.getPort());
						p2p_v_sendsocket.send(temppack);
//						mMainHandler.sendEmptyMessage(3);
					} else if (vmess.actiontype.equals("13")) {
						// 局域网,m->t->m->t
						VMESS tempvmess = new VMESS();
						tempvmess.actiontype = "14";
						String p2p_lan_sendm = Des.encryptDES(DataBuilder.buildJson(tempvmess), key, key);
						DatagramPacket temppack = new DatagramPacket(
								p2p_lan_sendm.getBytes(),
								p2p_lan_sendm.getBytes().length,
								pack.getAddress(), pack.getPort());
						p2p_v_sendsocket.send(temppack);
//						vport = "9001";
//						rport = "9002";
						// 应该发送数据了
						nip = pack.getAddress().toString().trim().substring(1);
//						mMainHandler.sendEmptyMessage(0);
					} else if (vmess.actiontype.equals("2")) {
						//收到了M发送过来证明自己在线的心跳
						if (recordrun) {
							lasttime = System.currentTimeMillis();
						}
					} else if (vmess.actiontype.equals("3")) {
//						mMainHandler.sendEmptyMessage(2);
						if (times_v == 0 || times_v == 1 || times_v == 2) {
							VMESS temp = new VMESS();
							temp.actiontype = "3";
							String xtjson = Des.encryptDES(DataBuilder.buildJson(temp), key, key);
							DatagramPacket temppack = new DatagramPacket(
									xtjson.getBytes(),xtjson.getBytes().length,
									pack.getAddress(), pack.getPort());
							p2p_v_sendsocket.send(temppack);
							if (times_v == 2){
								nip = pack.getAddress().getHostAddress();
								vport = ""+pack.getPort();
//								mMainHandler.sendEmptyMessage(0);
							}
						}
						times_v++;
					}else if (vmess.actiontype.equals("4")) {
						//收到n中转过来的m通知t停止播放的消息
						recordrun = false;
						lasttime = 0;
						if(udpsender!=null){
							udpsender.setIsstop(true);
						}
//						deinit();
					}
				} catch (Exception e) {

				}
			}
		}
	}
	
	public int getHeartBeatInterval() {
		return heartBeatInterval;
	}

	public void setHeartBeatInterval(int heartBeatInterval) {
		this.heartBeatInterval = heartBeatInterval;
	}

	public int getTerminalId() {
		return terminalId;
	}

	public void setTerminalId(int terminalId) {
		this.terminalId = terminalId;
	}

}
